﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using Bookkeeping.Core.Entities;
using Bookkeeping.Core.Persistence;
using NHibernate.Criterion;
using Bookkeeping.Core.Services;
using Bookkeeping.Persistence.Utilities.Extensions;
using NHibernate.Transform;

namespace Bookkeeping.Persistence.Repositories
{
    public class PostRepository : Repository<Post, int>, IPostRepository
    {
        public PostRepository() : base() { }
        public PostRepository(ISession session) : base(session) { }

        public IEnumerable<Post> GetSavings()
        {
            return GetByType(PostType.Saving);
        }

        public IEnumerable<Post> GetIncomes()
        {
            return GetByType(PostType.Income);
        }

        public IEnumerable<Post> GetExpenses()
        {
            return GetByType(PostType.Expense);
        }

        private IEnumerable<Post> GetByType(PostType type)
        {
            return Session.CreateCriteria<Post>()
                .Add(LambdaRestriction.Eq<Post>(p => p.Type, type))
                .List<Post>();
        }

        public IEnumerable<Post> GetExpensesByMonth(DateTime date)
        {
            return GetByTypeAndMonth(PostType.Expense, date);
        }

        public IEnumerable<Post> GetIncomesByMonth(DateTime date)
        {
            return GetByTypeAndMonth(PostType.Income, date);
        }

        public IEnumerable<Post> GetSavingsByMonth(DateTime date)
        {
            return GetByTypeAndMonth(PostType.Saving, date);
        }

        private IEnumerable<Post> GetByTypeAndMonth(PostType type, DateTime date)
        {
            DateTime firstDateTimeInMonth = DateTimeHelper.GetFirstDateTimeInMonth(date);
            DateTime lastDateTimeInMonth = DateTimeHelper.GetLastDateTimeInMonth(date);

            return Session.CreateCriteria<Post>()
                .Add(LambdaRestriction.Eq<Post>(p => p.Type, type))
                .Add(LambdaRestriction.Between<Post>(p => p.DateTime, firstDateTimeInMonth, lastDateTimeInMonth))
                .List<Post>();
        }

        public IEnumerable<Post> GetAllByMonth(DateTime date)
        {
            DateTime firstDateTimeInMonth = DateTimeHelper.GetFirstDateTimeInMonth(date);
            DateTime lastDateTimeInMonth = DateTimeHelper.GetLastDateTimeInMonth(date);

            return Session.CreateCriteria<Post>()
                .Add(LambdaRestriction.Between<Post>(p => p.DateTime, firstDateTimeInMonth, lastDateTimeInMonth))
                .List<Post>();
        }

        public IEnumerable<Post> GetAllByMonthWithTagsLoaded(DateTime date)
        {
            DateTime firstDateTimeInMonth = DateTimeHelper.GetFirstDateTimeInMonth(date);
            DateTime lastDateTimeInMonth = DateTimeHelper.GetLastDateTimeInMonth(date);

            return Session.CreateCriteria<Post>()
                .Add(LambdaRestriction.Between<Post>(p => p.DateTime, firstDateTimeInMonth, lastDateTimeInMonth))
                .SetFetchMode("Tags", FetchMode.Join)
                .SetResultTransformer(new DistinctRootEntityResultTransformer())
                .List<Post>();
        }
    }
}
